﻿/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#ifndef MK_MEDIA_Util_H
#define MK_MEDIA_Util_H
#include "MkUtil/MkBuffer.h"

#define MkAacAdtsLen        7
#define MkDefaultClockRate  90000    //default clock rate 90MHZ

typedef enum media_type
{
    MkCodecUnknown = 0x00,
    MkCodecMjpeg = 0x11,  //video Mjpeg
    MkCodecMpeg4 = 0x12,  //video mpeg4
    MkCodecYuv = 0x13,  //video YUV
    MkCodecH264 = 0x14,  //video h264
    MkCodecH265 = 0x15,  //video h265
    MkCodecH263 = 0x16,  //video h263
    MkCodecCavs = 0x49,  //video CAVS

    MkCodecAc3 = 0x51,  //audio ac3
    MkCodecG711u = 0x52,  //audio g711u
    MkCodecG711a = 0x53,  //audio g711a
    MkCodecG726 = 0x54,  //audio g726
    MkCodecG723 = 0x55,  //audio g723
    MkCodecAac = 0x56,  //audio AAC
    MkCodecPcm = 0x57,  //audio PCM
    MkCodecPcmLittle = 0x58,  //audio PCM little
    MkCodecMp3 = 0x59,  //audio mp3
    MkCodecSpeex = 0x6a,  //audio speex
    MkCodecDeviceSpc = 0x6b,  //audio device spec
} MkCodecType;

//RTMP video types
typedef enum _video_rtmp_codec_type
{
    MkVideoRtmpUnknow = 0,
    MkVideoRtmpH263 = 2,
    MkVideoRtmpScreenVideo = 3,
    MkVideoRtmpOn2Vp6 = 4,
    MkVideoRtmpOn2Vp6Alpha = 5,
    MkVideoRtmpScreenVideoV2 = 6,
    MkVideoRtmpAvc = 7,
    MkVideoRtmpHevC = 12
} MkRtmpVideoType;

//RTMP audio CODEC Type
typedef enum _audio_rtmp_codec_type
{
    MkAudioRtmpUnknow = -1,
    MkAudioRtmpLinearPcmPlatformEndian = 0,
    MkAudioRtmpADPcm = 1,
    MkAudioRtmpMp3 = 2,
    MkAudioRtmpLinearPcmLittleEndian = 3,
    MkAudioRtmpNellymoser16Hz = 4,
    MkAudioRtmpNellymoser8Hz = 5,
    MkAudioRtmpNellymoser = 6,
    MkAudioRtmpG711a = 7,
    MkAudioRtmpG711u = 8,
    MkAudioRtmpReserved = 9,
    MkAudioRtmpAac = 10,
    MkAudioRtmpSpeex = 11,
    MkAudioRtmpMp3_8Hz = 14,
    MkAudioRtmpDeviceSpec = 15
} MkRtmpAudioType;

typedef enum _audio_rate
{
    MkSampleRate96000Hz = 0,
    MkSampleRate88200Hz = 1,
    MkSampleRate64000Hz = 2,
    MkSampleRate48000Hz = 3,
    MkSampleRate44100Hz = 4,
    MkSampleRate32000Hz = 5,
    MkSampleRate24000Hz = 6,
    MkSampleRate22050Hz = 7,
    MkSampleRate16000Hz = 8,
    MkSampleRate12000Hz = 9,
    MkSampleRate11025Hz = 10,
    MkSampleRate8000Hz = 11,
    MkSampleRate7350Hz = 12,
    MkSampleRateReserved1 = 13,
    MkSampleRateReserved2 = 14,
    MkSampleRateFrequency = 15
} MkAudioSampleRate;

//from https://wiki.multimedia.cx/index.php?title=MPEG-4_Audio
typedef enum _aac_object_type
{
    MkAacObjectNull = 0,
    MkAacObjectMain = 1,
    MkAacObjectLc = 2,
    MkAacObjectSsr = 3,
    MkAacObjectLtp = 4,
    MkAacObjectSbr = 5,
    MkAacObjectAacScalable = 6,
    MkAacObjectTwinVQ = 7,
    MkAacObjectCelp = 8,
    MkAacObjectHxvc = 9,
    MkAacObjectReserved1 = 10,
    MkAacObjectReserved2 = 11,
    MkAacObjectTtsi = 12,
    MkAacObjectMainSynthesis = 13,
}MkAacObjectType;

typedef enum _audio_sample_size
{
    MkSampleSize8Bits = 0,
    MkSampleSize16Bits = 1,
    MkSampleSize32Bits = 2
} MkAudioSampleSize;

//for Nellymoser allays 0 .for AAC always 1
typedef enum _audio_stereo_type
{
    MkTypeSndMono = 0,
    MkTypeSndStereo = 1
}MkAudioSndType;

typedef enum _audio_packet_type
{
    MkAudioPacketHeader = 0,
    MkAudioPacketFrameData = 1
}MkAudioPacketType;

typedef enum _hevc_nalu_type
{
    MkHevcNalTrailN = 0,
    MkHevcNalTrailR = 1,
    MkHevcNalTsaN = 2,
    MkHevcNalTsaR = 3,
    MkHevcNalStsaN = 4,
    MkHevcNalStsaR = 5,
    MkHevcNalRadlN = 6,
    MkHevcNalRadlR = 7,
    MkHevcNalRaslN = 8,
    MkHevcNalRaslR = 9,
    MkHevcNalVclN10 = 10,
    MkHevcNalVclN11 = 11,
    MkHevcNalVclN12 = 12,
    MkHevcNalVclN13 = 13,
    MkHevcNalVclN14 = 14,
    MkHevcNalVclN15 = 15,
    MkHevcNalBlaWLp = 16,
    MkHevcNalBlaWRadl = 17,
    MkHevcNalBlaNLp = 18,
    MkHevcNalIdrWRadl = 19,
    MkHevcNalIdrNLp = 20,
    MkHevcNalCraNut = 21,
    MkHevcNalIrapVcl22 = 22,
    MkHevcNalIrapVcl23 = 23,
    MkHevcNalRsvVcl24 = 24,
    MkHevcNalRsvVcl25 = 25,
    MkHevcNalRsvVcl26 = 26,
    MkHevcNalRsvVcl27 = 27,
    MkHevcNalRsvVcl28 = 28,
    MkHevcNalRsvVcl29 = 29,
    MkHevcNalRsvVcl30 = 30,
    MkHevcNalRsvVcl31 = 31,
    MkHevcNalVps = 32,
    MkHevcNalSps = 33,
    MkHevcNalPps = 34,
    MkHevcNalAud = 35,
    MkHevcNalEosNut = 36,
    MkHevcNalEobNut = 37,
    MkHevcNalFdNut = 38,
    MkHevcNalSeiPrefix = 39,
    MkHevcNalSeiSuffix = 40,
    //https://datatracker.ietf.org/doc/html/rfc7798#section-4.4
    MkHevcPacketAp = 48,
    MkHevcPacketPaci = 49
}MkHevcNaluType;

typedef enum _h264_nalu_type
{
    MkH264NalUnspeciFied0 = 0,
    MkH264NalSlice = 1,
    MkH264NalDpa = 2,
    MkH264NalDpb = 3,
    MkH264NalDpc = 4,
    MkH264NalIdrSlice = 5,
    MkH264NalSei = 6,
    MkH264NalSps = 7,
    MkH264NalPps = 8,
    MkH264NalAud = 9,
    MkH264NalEndSequence = 10,
    MkH264NalEndStream = 11,
    MkH264NalFilterData = 12,
    MkH264NalSpsExt = 13,
    MkH264NalPrefix = 14,
    MkH264NalSubSps = 15,
    MkH264NalDps = 16,
    MkH264NalReserved17 = 17,
    MkH264NalReserved18 = 18,
    MkH264NalAuxiliarySlice = 19,
    MkH264NalExtenSlice = 20,
    MkH264NalDepthExtenSlice = 21,
    MkH264NalReserved22 = 22,
    MkH264NalReserved23 = 23,
    MkH264NalUnspeciFied24 = 24,
    MkH264NalUnspeciFied25 = 25,
    MkH264NalUnspeciFied26 = 26,
    MkH264NalUnspeciFied27 = 27,
    MkH264NalUnspeciFied28 = 28,
    MkH264NalUnspeciFied29 = 29,
    MkH264NalUnspeciFied30 = 30,
    MkH264NalUnspeciFied31 = 31,
}MkH264NaluType;

//https://www.rfc-editor.org/rfc/rfc6184.html#section-5.4
typedef enum _h264_packet_type
{
    MkH264PacketUnknow = 0,
    MkH264PacketSingle = 23,
    MkH264PacketStapA = 24,
    MkH264PacketStapB = 25,
    MkH264PacketMtap16 = 26,
    MkH264PacketMtap24 = 27,
    MkH264PacketFuA = 28,
    MkH264PacketFuB = 29
}MkH264PacketType;

typedef enum  _flv_tag_type
{
    MkFlvTagAudio = 8,
    MkFlvTagVideo = 9,
    MkFlvTagScript = 18
}MkFlvTagType;

typedef enum _flv_video_frame_type
{
    MkFlvVideoKeyFrame = 1,
    MkFlvVideoInterFrame = 2,
    MkFlvVideoDisposableInterFrame = 3, //h263 only
    MkFlvVideoGeneratedKeyFrame = 4,
    MkFlvVideoInfoFrame = 5,
}MkFlvVideoFrameType;

typedef enum _flv_avc_packet_type
{
    MkFlvAvcPacketSequenceHeader = 0,
    MkFlvAvcPacketNalu = 1,
    MkFlvAvcPacketEndSequence = 2
}MkFlvAvcPacketType;

typedef enum _media_source_type
{
    MkMediaSourceFile264,
    MkMediaSourceFilePs,
    MkMediaSourceFileH265,
    MkMediaSourceFileFlv,
    MkMediaSourceFileAac,
    MkMediaSourceRtmpPlayer,
    MkMediaSourceRtmpPublisher,
    MkMediaSourceRtspPlayer,
    MkMediaSourceFlvPlayer,
    MkMediaSourceStreamPs,
    MkMediaSourceStreamH264,
    MkMediaSourceStreamH265
}MkMediaSourceType;

typedef enum _media_consume_type
{
    MkMediaConsumeWsFlv,
    MkMediaConsumeRtmp,
    MkMediaConsumeRtsp,
    MkMediaConsumeGb
}MkMediaConsumeType;

typedef enum _playback_control_type
{
    MkControlUnknown = 0x00,
    MkControlPause,
    MkControlSeek,
    MkControlSetSpeed,
    MkControlRecovery,
}MkPlaybackControlType;

typedef struct _es_packet
{
    Uint32          Dts;        //Decoding Time Stamp  Millisecond
    Uint32          Pts;        //Presentation Time Stamp Millisecond
    MkCodecType     CodecType;
    CMkBufferList   BufferList;
    BOOL            bKeyPacket;
    _es_packet()
    {
        Pts = 0;
        Dts = 0;
        CodecType = MkCodecUnknown;
        bKeyPacket = FALSE;
    }
}MkEsPacket;  //when pData null or nsize 0  end

typedef struct _cache_es_packet
{
    Uint32                  Pts;
    Uint32                  Dts;
    MkCodecType             CodecType;
    BOOL                    bKeyPacket;
    CMkStorageBufferList    CacheBufferList;
}MkCacheEsPacket;

typedef struct _cache_stream_packet
{
    Uint32                  Pts;
    Uint32                  Dts;
    MkCodecType             CodecType;
    BOOL                    bKeyPacket;
    CMkStorageBufferList    CacheBufferList;
}MkCacheStreamPacket;
typedef MkList<MkCacheStreamPacket> MkListCacheStreamPacket;

typedef struct _frame
{
    Uint8       *pY;
    Uint8       *pU;
    Uint8       *pV;
    Uint32      Height;
    Uint32      Width;
    Uint32      FrameType;
    Uint32      TimeStamp;
    Uint32      StrideY;
    Uint32      StrideUv;
    _frame()
    {
        pY = pV = pU = nullptr;
        Height = Width = FrameType = TimeStamp = StrideY = StrideUv = 0;
    }
} MkFrame;

typedef struct _special_nalu
{
    Uint8       NaluType;
    MkString    NaluData;
}MkSpecialNalu;

#define MkFlvHeaderSize 9
#define MkFlvTagHeaderSize 11
extern const MkApi Uint32 NaluStartCode;

class MkApi CMkMediaUtil
{
public:
    ~CMkMediaUtil() {}
    static CMkMediaUtil& GetInstance() { return m_Instance; }
    static MkAudioSampleRate AudioSampleRateToIndex(Uint32 SampleRate);
    static Uint32 AudioSampleRateIndexToRate(const MkAudioSampleRate& RateIndex);
    static MkAudioSampleSize AudioSampleSizeToIndex(Uint8 SampleSize);
    static Uint8 AudioSampleSizeIndexToSize(const MkAudioSampleSize& SizeIndex);
    static MkCodecType RtmpAudioTypeToCodec(const MkRtmpAudioType& RtmpAudioType);
    static MkCodecType RtmpVideoTypeToCodec(const MkRtmpVideoType& RtmpVideoType);
    static MkRtmpAudioType CodecToRtmpAuidoType(const MkCodecType& Codec);
    static MkRtmpVideoType CodecToRtmpVideoType(const MkCodecType& Codec);
    //static Uint32 CreateAacAdts(const MkAudioParam& AudioParam, Uint16 nLen, MkString& strAdts);
    static Uint32 Get264NaluType(const Uint8& NaluHeader, Uint8 &NaluType);
    static Uint32 Get265NaluType(const Uint8& NaluHeader, Uint8 &NaluType);
    static Uint32 GuessCodecType(const Uint8& NaluHeader, MkCodecType& Codec);
    //static Uint32 H26xSplitNaluPacket(MkEsPacket& Packet, MkVector<MkEsPacket>& VecPacket);
    static Uint32 GetNextH26xNalu(const Uint8* pBegin, const Uint8* pEnd, Uint8 const **pLastNaluEnd, Uint8  const** pNaluHeader);
    static BOOL IsPacketFrame(Uint8 NaluType);
    static Uint32 WriteFrameToFile(const MkString& FileName, const MkFrame& Frame);
    static Uint32 H264SpsParse(const Uint8 *pInput, Uint32 nLen, Uint32 &nWidth, Uint32 &nHeight, Uint32 &nFrameRate);
    static Uint32 H265SpsParse(const Uint8 *pInput, Uint32 nLen, Uint32 &nWidth, Uint32 &nHeight);
    static Uint32 H265VpsParse(const Uint8 *pInput, Uint32 nLen, Uint32 &nFrameRate);
    static void DeEmulationPrevention(Uint8 *buf, unsigned int *buf_size);
    static Uint32 WriteCacheEsPacket(const MkEsPacket& EsPacket, MkCacheEsPacket& CacheEsPacket);
    static Uint32 ReadCachePacket(const MkCacheEsPacket& CacheEsPacket, MkEsPacket& EsPacket);
    static Uint32 WriteCacheStream(const MkEsPacket& EsPacket, const CMkBufferList& StreamBufferList, MkCacheStreamPacket& CacheStreamPacket);
    static Uint32 GetAacAdtsFrame(const Uint8* pInput, Uint32 nLen, const Uint8** pAdts, Uint32& AdtsLen, Uint32& nUsed);
    //pAdts size mast more than MkAacAdtsLen
    static Uint32 CreateAacAdts(const MkAacObjectType& ObjectType, const MkAudioSampleRate& SampleRate, const Uint8& nChannel, Uint32 AacRawLen, OUT Uint8* pAdts);
    static Uint32 AacAdtsParse(const Uint8* pBuf, Uint32 nLen, MkAacObjectType& ObjectType, MkAudioSampleRate& SampleRate, Uint8& nChannel);
    static Uint64 GetAverageSpeed(Uint64 TatolBytes, const CMkTime& StartTime, const CMkTime& EndTime = NowMkTime);
    const MkString& GetStringMediaSourceType(const MkMediaSourceType& SourceType) const;
    const MkString& GetStringMediaConsumerType(const MkMediaConsumeType& ConsumerType) const;
    const MkString& GetStringCodec(const MkCodecType& Codec) const;
    MkCodecType GetCodec(const MkString& strCodec) const;
    const MkUnorderedMap<MkString, MkPlaybackControlType>& GetMapPlaycontrolType() const { return m_MapPlaycontrolType; }
    MkPlaybackControlType GetPlaybackControlType(const MkString& StringControlType) const;

private:
    static Uint32 Ue(Uint8 *pBuff, Uint32 nLen, Uint32 &nStartBit);
    static int Se(Uint8 *pBuff, Uint32 nLen, Uint32 &nStartBit);
    static Uint32 u(Uint32 BitCount, Uint8 *buf, Uint32 &nStartBit);
    CMkMediaUtil();
private:
    static CMkMediaUtil                                 m_Instance;
    MkUnorderedMap<Uint32, MkString>                    m_MapMediaSourceType;
    MkUnorderedMap<Uint32, MkString>                    m_MapCodec;
    MkUnorderedMap<MkString, MkPlaybackControlType>     m_MapPlaycontrolType;
    MkUnorderedMap<Uint32, MkString>                    m_MapMediaConsumerType;
};


class MkApi CMkVideoParam
{
public:
    CMkVideoParam();
    CMkVideoParam(const MkCodecType& Codec, const Uint32& Width, const Uint32& Height, const Uint32& FrameRate, const Uint32& BitRate);
    virtual ~CMkVideoParam() {};

    const MkCodecType& GetCodec() const { return m_Codec; }
    const Uint32& GetWidth() const { return m_Width; }
    const Uint32& GetHeight() const { return m_Height; }
    const Uint32& GetFrameRate() const { return m_FrameRate; }
    const Uint32& GetBitRate() const { return m_BitRate; }

    void SetCodec(const MkCodecType& Codec) { m_Codec = Codec; }
    void SetWidth(const Uint32& Width) { m_Width = Width; }
    void SetHeight(const Uint32& Height) { m_Height = Height; }
    void SetFrameRate(const Uint32& FrameRate) { m_FrameRate = FrameRate; }
    void SetBitRate(const Uint32& BitRate) { m_BitRate = BitRate; }

    const MkString& GetSps() const { return m_Sps; }
    const MkString& GetPps() const { return m_Pps; }
    const MkString& GetVps() const { return m_Vps; }
    void SetPps(const MkString& Pps) { m_Pps = Pps; }
    void SetSps(const MkString& Sps) { m_Sps = Sps; }
    void SetVps(const MkString& Vps) { m_Vps = Vps; }

    void SetCurTimeStamp(const Uint32& CurTimeStamp) { m_CurTimeStamp = CurTimeStamp; }
    const Uint32& GetCurTimeStamp() const { return m_CurTimeStamp; }
private:
    MkCodecType m_Codec;
    Uint32      m_Width;
    Uint32      m_Height;
    Uint32      m_FrameRate;
    Uint32      m_BitRate;

    Uint32      m_CurTimeStamp;
    //h265 and h264
    MkString    m_Sps;
    MkString    m_Pps;

    //h265
    MkString    m_Vps;
};

class MkApi CMkAudioParam
{
public:
    CMkAudioParam();
    CMkAudioParam(const MkCodecType& Codec, const Uint32& BitRate, const MkAudioSampleRate& SampleRate, const MkAudioSampleSize& SampleSize, const BOOL& bStereo, const Uint8& Channel);
    virtual ~CMkAudioParam() {};
    const MkCodecType& GetCodec() const { return m_Codec; }
    const Uint8& GetChannel() const { return m_Channel; }
    const Uint32& GetBitRate() const { return m_BitRate; }
    const MkAudioSampleRate& GetSampleRate() const { return m_SampleRate; }
    const MkAudioSampleSize& GetSampleSize() const { return m_SampleSize; }
    const BOOL& GetStereo() const { return m_bStereo; }
    void SetCodec(const MkCodecType& Codec) { m_Codec = Codec; }
    void SetChannel(const Uint8& Channel) { m_Channel = Channel; }
    void SetBitRate(const Uint32& BitRate) { m_BitRate = BitRate; }
    void SetSampletRate(const MkAudioSampleRate& SampleRate) { m_SampleRate = SampleRate; }
    void SetSampleSize(const MkAudioSampleSize& SampleSize) { m_SampleSize = SampleSize; }
    void SetStereo(const BOOL& bStereo) { m_bStereo = bStereo; }

    void SetObjectType(const MkAacObjectType& ObjType) { m_ObjectType = ObjType; }
    void SetFrameLenghFlag(const Uint8& FrameLenghFlag) { m_FrameLenghFlag = FrameLenghFlag; }
    void SetDependOnCoreCoder(const Uint8& DependOnCoreCoder) { m_DependOnCoreCoder = DependOnCoreCoder; }
    void SetExternsionFlag(const Uint8& ExternsionFlag) { m_ExternsionFlag = ExternsionFlag; }
    const MkAacObjectType& GetObjectType() const { return m_ObjectType; }
    const Uint8& GetDependOnCoreCoder() const { return m_DependOnCoreCoder; }
    const Uint8& GetFrameLenghFlag() const { return m_FrameLenghFlag; }
    const Uint8& GetExternsionFlag() const { return m_ExternsionFlag; }
    void SetCurTimeStamp(const Uint32& CurTimeStamp) { m_CurTimeStamp = CurTimeStamp; }
    const Uint32& GetCurTimeStamp() const { return m_CurTimeStamp; }
protected:
private:
    MkCodecType         m_Codec;
    Uint32              m_BitRate;
    MkAudioSampleRate   m_SampleRate;
    MkAudioSampleSize   m_SampleSize;
    BOOL                m_bStereo;
    Uint8               m_Channel;

    Uint32              m_CurTimeStamp;

    //aac use
    MkAacObjectType     m_ObjectType;
    Uint8               m_FrameLenghFlag;
    Uint8               m_DependOnCoreCoder;
    Uint8               m_ExternsionFlag;
};

#endif
